import { cloneDeep, keyBy, last, remove } from "lodash";
import { generateUuid } from "@/utils/common";
import { fetchEventSource } from "@microsoft/fetch-event-source";
import store from "store2";
import { IQItem, IRecommendationContent } from "@/pages/BigScreen/context/type";

export const DEFAULT_RECOMMENDED_NUMBER = 4;
export const DEFAULT_TITLE = "您好";
export const DEFAULT_CHAT_CONTENT = "WHAT_CAN_I_DO_FOR_YOU";

export const chatPageSize = 8;

/**
 * @CHAT_ROLE 会话角色
 */
export enum CHAT_ROLE {
  /**
   * @user 提问者
   */
  user = "user",
  /**
   * @assistant ai
   */
  assistant = "assistant",
  /**
   * @view 回答间隙预览
   */
  view = "view",
  error = "error",
}

/**
 * @DEVICE_TYPE 设备类型
 */
export enum DEVICE_TYPE {
  /**
   * @web 网页
   */
  web = "web",
  /**
   * @pc pc客户端
   */
  pc = "pc",
  /**
   * @app 手机APP
   */
  app = "app",
  /**
   * @wechatMiniProgram 微信小程序
   */
  wechatMiniProgram = "wechatMiniProgram",
}

export type deviceType = {
  readonly [K in keyof typeof DEVICE_TYPE]: K;
};
/**
 * @SESSION_TYPE 会话类型
 */
export enum SESSION_TYPE {
  /**
   * @text_chat 文本会话
   */
  text_chat = "text_chat",
  /**
   * @image_chat 图片会话
   */
  image_chat = "image_chat",
  /**
   * @file_chat 文件会话
   */
  file_chat = "file_chat",
}

/**
 * @CHAT_EVENT chunk event
 */
export enum CHAT_EVENT {
  ERROR = "ERROR",
  MESSAGE = "MESSAGE",
  DONE = "DONE",
  PING = "PING",
}

/**
 * @CHAT_ACTION 会话行为
 */
export enum CHAT_ACTION {
  /**
   * @next 下一个
   */
  next = "next",
  /**
   * @variant 重新生成
   */
  variant = "variant",
}

export const DEFAULT_RECOMMEND_LIST: IRecommendationContent[] = [
  {
    content: "H-K方法在计算微孔分布时基于什么假设？",
    type: 0,
  },
  {
    content: "TPFSD方法除了定量吸附数据，还有哪些优点",
    type: 0,
  },
  {
    content: "如何测定催化剂活性中心性质？",
    type: 0,
  },
  {
    content: "金属氧化物与金属相比，为什么在催化反应中应用更广泛？",
    type: 0,
  },
  // {
  //   content: "SiO₂上吸附的吡啶的拉曼光谱有哪些特点？请详细描述。",
  //   type: 0,
  // },
  // {
  //   content: "催化剂活性中心的性质包括哪些方面？",
  //   type: 0,
  // },
];

// 初始化展示的列表内容
export const DEFAULT_Q_LIST = [
  {
    id: generateUuid(),
    role: CHAT_ROLE.assistant,
    childMsgId: [],
    interrupted: false,
    messageBody: {
      chartData: {},
      contents: [
        {
          content: DEFAULT_TITLE,
          role: CHAT_ROLE.assistant,
        },
      ],
      recommended: {
        chatId: "",
        clientId: "Recommendation",
        content: DEFAULT_RECOMMEND_LIST,
      },
    },
    msgId: "",
    parentMsgId: "",
    sessionId: "",
    // 是否是初始化新对话的提示
    isInitChat: true,
  },
];

// 初始化展示的列表内容, 国际版参数传入,不然还是第一次加载的
export const getDefault_q_list = (
  title = DEFAULT_TITLE,
  desc = DEFAULT_RECOMMEND_LIST
) => {
  return [
    {
      id: generateUuid(),
      role: CHAT_ROLE.assistant,
      childMsgId: [],
      interrupted: false,
      messageBody: {
        chartData: {},
        contents: [
          {
            content: title,
            role: CHAT_ROLE.assistant,
          },
        ],
        recommended: {
          chatId: "",
          clientId: "Recommendation",
          content: desc,
        },
      },
      msgId: "",
      parentMsgId: "",
      sessionId: "",
      // 是否是初始化新对话的提示
      isInitChat: true,
    },
  ];
};

export const DEFAULT_ERROR_ITEM = {
  id: generateUuid(),
  role: CHAT_ROLE.view,
  messageBody: {
    chartData: {},
    contents: [
      {
        content: ``,
        contentType: "text",
        role: CHAT_ROLE.assistant,
      },
    ],
  },
};

interface IGetDefaultQuestionList {
  recommendedList: Array<string>;
  title?: string;
}
/**
 * @description: 获取默认的对话列表
 * @param {Array} recommendedList 推荐列表
 * @return {*}
 */
export const getDefaultQuestionList = (props: IGetDefaultQuestionList) => {
  const { recommendedList, title = "" } = props;
  const id = generateUuid();
  return [
    {
      id: id,
      role: CHAT_ROLE.assistant,
      childMsgId: [],
      interrupted: false,
      messageBody: {
        chartData: {},
        contents: [
          {
            content: title || DEFAULT_TITLE,
            role: CHAT_ROLE.assistant,
          },
        ],
        recommended: {
          chatId: "",
          clientId: "Recommendation",
          content: recommendedList || DEFAULT_RECOMMEND_LIST,
        },
      },
      msgId: id,
      parentMsgId: "",
      sessionId: "",
      // 是否是初始化新对话的提示
      isInitChat: true,
    },
  ];
};

/**
 * @description: 获取对话项的文本内容
 * @param {IQItem} item
 * @return {*} content
 */
export const getChatItemContent = (item: IQItem) => {
  const chatContent = item?.messageBody?.contents?.[0]?.content ?? "";
  return chatContent;
};

export interface IChatHistoryItem {
  id: string;
  content?: string;
}

export const getNewChat = () => {
  return store.get("supcon.bs.isNewChat") || false;
};
export const setNewChat = () => {
  store.set("supcon.bs.isNewChat", true);
};
export const clearNewChat = () => {
  store.set("supcon.bs.isNewChat", false);
};

export const addChatHistory = (chat: IChatHistoryItem) => {
  let oldChatHistory = store.get("supcon.bs.chatHistory") || [];
  oldChatHistory.unshift(chat);
  store.set("supcon.bs.chatHistory", oldChatHistory);
};
export const setChatHistory = (chatList: Array<IChatHistoryItem>) => {
  store.set("supcon.bs.chatHistory", chatList);
};

export const destoryChatHistory = (id: string) => {
  let oldChatHistory = store.get("supcon.bs.chatHistory") || [];
  let newChatHistory = remove(
    oldChatHistory,
    function (chat: IChatHistoryItem) {
      return chat.id == id;
    }
  );
  store.set("supcon.bs.chatHistory", newChatHistory);
};

export const selectChatHistoryItem = (item: IChatHistoryItem) => {
  store.set("supcon.bs.chatContext", item);
};
export const updateHistoryById = (id: string, newItem: IChatHistoryItem) => {
  let cHistoryList = store.get("supcon.bs.chatHistory") || [];
  let newHistoryList = cHistoryList.map((item: IChatHistoryItem) => {
    if (item.id == id) {
      return { ...item, ...newItem };
    } else {
      return item;
    }
  });
  store.set("supcon.bs.chatHistory", newHistoryList);
};

export const clearChatContext = () => {
  store.set("supcon.bs.chatContext", {});
};

export const clearChatHistory = () => {
  store.set("supcon.bs.chatHistory", []);
};

export const clearAllChat = () => {
  clearChatContext();
  clearChatHistory();
};

export function parseMessage(str: any): IQItem {
  try {
    const resStr = JSON.parse(str);
    if (
      resStr &&
      resStr.messageBody &&
      resStr.messageBody.contents &&
      resStr.messageBody.contents[0] &&
      resStr.messageBody.contents[0].content
    ) {
      const currContent = resStr.messageBody.contents[0];
      const repalceStr = currContent.content.replaceAll("\\n", "\n");
      currContent.content = repalceStr;
    }
    return resStr;
  } catch (err) {
    throw new Error("数据解析失败");
  }
}

export function extractMarkdownText(markdownText: string) {
  // 首先移除所有的 ::: supgptcode 标签及其内容
  const supgptcodeRegex = /:::\s*supgptcode[\s\S]*?:::/g;
  markdownText = markdownText.replace(supgptcodeRegex, "");
  // 移除所有的 <hr> 标签
  const hrRegex = /<hr\s*\/?>/gi;
  markdownText = markdownText.replace(hrRegex, "");
  // 正则表达式匹配Markdown标题或段落
  const blockRegex = /^(#+\s*(.*)|\s*([^#]+)\s*)$/gm;
  let concatenatedText = "";
  let match;
  while ((match = blockRegex.exec(markdownText)) !== null) {
    if (match[2]) {
      // 如果是标题
      concatenatedText += match[2].trim() + "\n\n";
    } else if (match[3]) {
      // 如果是段落，清除段落中的多余空白字符
      const paragraph = match[3].replace(/\s+/g, " ").trim();
      if (paragraph) {
        concatenatedText += paragraph + "\n\n";
      }
    }
  }
  // 移除最后的额外换行符
  concatenatedText = concatenatedText.trim();
  return concatenatedText;
}
type Role = "user" | "system" | "assistant";

interface ConversationContents {
  role: Role;
  content: string;
  contentType: string;
}
interface SceneInfoType {
  id: string;
  name: string;
  type: string;
}
export function fetchConversation(
  params: {
    action: string;
    contents?: ConversationContents[];
    msgId: string;
    parentMsgId: string;
    jobSceneAnswerMsgId?: string;
    deviceType: string;
    sessionId: string;
    sessionType: string;
    variantMsgId?: string;
    pluginIds?: string[];
    scene?: SceneInfoType & {
      params?: any;
    };
  },
  controller: AbortController,
  onMessage?: (data: any, history: any) => void
) {
  return new Promise((reslove, reject) => {
    let history: any[] = [];
    let token = store.get("token");
    let otsToken = store.get("supcon.ots.token");
    let localeLang = "zh-CN";
    const url = "/cnpc-web/chat-tool-chat/api/conversation";
    const headers = {
      "x-app": "gpt", // 自建应用
      accept: "application/json, text/plain, */*",
      "Content-Type": "application/json",
      "Accept-Language": localeLang,
    };
    if (token) {
      headers["Authorization"] = `Bearer ${token ? token.replace(/^"|"$/g, "") : ""
        }`;
    }
    // if (adapterToken) {
    //   headers["Authorization"] = `Trust ${
    //     adapterToken ? adapterToken.replace(/^"|"$/g, "") : ""
    //   }`;
    // }
    if (otsToken) {
      headers["Authorization-Ots"] = `Bearer ${otsToken.replace(/^"|"$/g, "")}`;
    }

    let originData: any = {};
    const mergeMessageData = (mergeData: any) => {
      const messageKeys = [
        "msgId",
        "id",
        "messageBody",
        "sessionId",
        "parentMsgId",
      ];
      const thinkKeys = ["agentId", "agentName", "chatId"];
      const mergeKeys = Object.keys(mergeData);
      const isMessage = messageKeys.every((i) => mergeKeys.includes(i));
      const isThink = thinkKeys.every((i) => mergeKeys.includes(i));
      if (isMessage) {
        originData = mergeData;
      } else if (isThink) {
        if (originData.messageBody) {
          const newOriginData = cloneDeep(originData);
          if (newOriginData.messageBody.thinks) {
            const originThinks = newOriginData.messageBody.thinks;
            const findThinkIndex = originThinks.findIndex(
              (i: any) => i.agentId === mergeData.agentId
            );
            if (findThinkIndex === -1) {
              originThinks.push(mergeData);
              newOriginData.messageBody.thinks = originThinks;
            } else {
              const { leftContent, rightContent, ...other } = mergeData;
              const mergeItem =
                newOriginData.messageBody.thinks[findThinkIndex];
              newOriginData.messageBody.thinks[findThinkIndex] = {
                ...mergeItem,
                ...other,
                leftContent: mergeItem.leftContent + leftContent,
                rightContent: mergeItem.rightContent + rightContent,
              };
            }
          } else {
            newOriginData.messageBody.thinks = [mergeData];
          }
          originData = newOriginData;
        }
      }
    };

    fetchEventSource(url, {
      method: "POST",
      headers: {
        ...headers,
      },
      body: JSON.stringify({
        data: params,
      }),
      signal: controller.signal,
      openWhenHidden: true,
      onopen: async (response: any) => {
        const contentType = response.headers.get("content-type");
        if (!contentType?.startsWith("text/event-stream")) {
          const reader = response.body.getReader();
          const result = await reader.read();
          const decoder = new TextDecoder();
          const field = decoder.decode(result.value);
          const res = JSON.parse(field);
          // if (res.code === "A0230") {
          //   await fetchRefreshToken();
          // }
          if (res && !res.success) throw res;
        }
      },
      onclose() {
        console.log("onclose 111");
        reslove(history);
      },
      onerror(err) {
        console.log("onerror 111", err);
        controller.abort();
        const viewIndex = history.findIndex((i) => i.role === "error");
        if (viewIndex !== -1) {
          history[viewIndex].context = err;
        } else {
          history.push({ role: "error", context: err });
        }
        throw err;
      },
      onmessage: (event: any) => {
        if (event.data === "[DONE]") {
          // ctrl.abort();
        } else if (event.event === "[ERROR]") {
          //ctrl.abort();
          const viewIndex = history.findIndex((i) => i.role === "error");
          const resError =
            typeof event.data === "string"
              ? {
                msg: event.data,
              }
              : event.data;
          if (viewIndex !== -1) {
            history[viewIndex].context = resError;
          } else {
            history.push({ role: "error", context: resError });
          }
          reslove(history);
        } else if (event.event === "[PING]") {
          //ctrl.abort();
        } else if (event.event === "[MESSAGE]") {
          if (event.data) {
            const resMessageData = parseMessage(event.data);
            mergeMessageData(resMessageData);
            const viewIndex = history.findIndex((i) => i.role === "view");
            if (viewIndex !== -1) {
              history[viewIndex].context = originData;
            } else {
              history.push({ role: "view", context: originData });
            }
            onMessage && onMessage(originData, history);
          }
        }
      },
    }).then(
      () => {
        reslove(history);
      },
      (err) => {
        reject(err);
      }
    );
  });
}

export function getChat(content: IQItem[]) {
  // const content: any = await this.chatStore.getChatBySessionId(sessionId)
  const arr: IQItem[] = [];
  let chatSourceMap: Record<string, IQItem> = {};
  const getChild = (item: any) => {
    if (item.messageBody.contents[0].role === "assistant") {
      if (item.childMsgId && item.childMsgId.length > 0) {
        for (let i = 0; i < item.childMsgId.length; i++) {
          const childItem = chatSourceMap[item.childMsgId[i]];
          if (childItem) getChild(childItem);
        }
      }
    } else {
      if (item.childMsgId && item.childMsgId.length > 0) {
        for (let i = 0; i < item.childMsgId.length; i++) {
          const childItem = chatSourceMap[item.childMsgId[i]];
          if (childItem) {
            arr.push(item);
            arr.push(childItem);
          }
        }
        for (let i = 0; i < item.childMsgId.length; i++) {
          const childItem = chatSourceMap[item.childMsgId[i]];
          if (childItem) {
            getChild(childItem);
          }
        }
      }
    }
  };
  if (content) {
    chatSourceMap = keyBy(content, "msgId");
    const firstMessage = content.filter((i: any) => i.parentMsgId === "0");
    if (firstMessage && firstMessage.length > 0) {
      firstMessage.forEach((item: any) => {
        getChild(item);
      });
    }
  }
  return arr.map((item, index) => {
    return {
      ...item,
      chatIndex: index,
    };
  });
}
